﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using YJKArchMethodLibrary.Utils;
using YJKRevitCode.RevitObjectCompareUtility;

namespace YJKArchMethodLibrary.Common
{
	public class EdgeLoopAnalyser
	{
		public static bool SerializeEdgesToLoop(List<LoopEdge> edges, ref List<LoopEdge> serializedEdges, ref string message)
		{
			if (edges.Count == 1)
			{
				message = "所选参照线不闭合";
				return false;
			}
			Dictionary<XYZ, List<LoopEdge>> dictionary = new Dictionary<XYZ, List<LoopEdge>>(new XYZEqualityComparer());
			foreach (LoopEdge loopEdge in edges)
			{
				XYZ startPoint = loopEdge.StartPoint;
				XYZ endPoint = loopEdge.EndPoint;
				if (!dictionary.ContainsKey(startPoint))
				{
					dictionary.Add(startPoint, new List<LoopEdge>
					{
						loopEdge
					});
				}
				else
				{
					List<LoopEdge> list = dictionary[startPoint];
					list.Add(loopEdge);
				}
				if (!dictionary.ContainsKey(endPoint))
				{
					dictionary.Add(endPoint, new List<LoopEdge>
					{
						loopEdge
					});
				}
				else
				{
					List<LoopEdge> list2 = dictionary[endPoint];
					list2.Add(loopEdge);
				}
			}
			XYZ xyz = null;
			foreach (KeyValuePair<XYZ, List<LoopEdge>> keyValuePair in dictionary)
			{
				XYZ key = keyValuePair.Key;
				if (xyz == null)
				{
					xyz = key;
				}
				List<LoopEdge> value = keyValuePair.Value;
				if (value.Count > 2)
				{
					message = "所选参照线存在多个分支，无法形成封闭区域";
					return false;
				}
				if (value.Count == 1)
				{
					message = "所选参照线不闭合";
					return false;
				}
			}
			List<LoopEdge> list3 = new List<LoopEdge>();
			XYZ xyz2 = xyz;
			XYZ xyz3 = null;
			double previousEdgeBugle = 0.0;
			while (dictionary.ContainsKey(xyz2))
			{
				List<LoopEdge> list4 = dictionary[xyz2];
				if (xyz3 == null)
				{
					xyz3 = EdgeLoopAnalyser.GetOtherPoint(list4[0], xyz2);
					previousEdgeBugle = list4[0].Bulge;
				}
				LoopEdge loopEdge2 = null;
				XYZ nextPoint = EdgeLoopAnalyser.GetNextPoint(xyz2, list4, xyz3, previousEdgeBugle, ref loopEdge2);
				if (loopEdge2 != null)
				{
					LoopEdge item = EdgeLoopAnalyser.SerializeEdge(loopEdge2, xyz3);
					list3.Add(item);
				}
				if (nextPoint == null)
				{
					return false;
				}
				if (nextPoint.IsAlmostEqualTo(xyz))
				{
					break;
				}
				xyz3 = xyz2;
				xyz2 = nextPoint;
				previousEdgeBugle = loopEdge2.Bulge;
			}
			serializedEdges.AddRange(list3);
			return true;
		}

		public static bool JudgeRightHandwise(List<XYZ> loopEdgeVertex, ref EdgeLoopAnalyser.RightHandwise direction)
		{
			int count = loopEdgeVertex.Count;
			if (count < 3)
			{
				return false;
			}
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < count; i++)
			{
				XYZ xyz = loopEdgeVertex[i];
				XYZ xyz2;
				XYZ xyz3;
				if (i == 0)
				{
					xyz2 = loopEdgeVertex[count - 1];
					xyz3 = loopEdgeVertex[i + 1];
				}
				else if (i == count - 1)
				{
					xyz2 = loopEdgeVertex[i - 1];
					xyz3 = loopEdgeVertex[0];
				}
				else
				{
					xyz2 = loopEdgeVertex[i - 1];
					xyz3 = loopEdgeVertex[i + 1];
				}
				XYZ xyz4 = (xyz3 - xyz).CrossProduct(xyz2 - xyz).Normalize();
				if (xyz4.IsAlmostEqualTo(XYZ.BasisZ))
				{
					num++;
				}
				else if (xyz4.IsAlmostEqualTo(-XYZ.BasisZ))
				{
					num2++;
				}
			}
			if (num == num2)
			{
				List<XYZ> list = new List<XYZ>();
				for (int i = 0; i < loopEdgeVertex.Count; i += 2)
				{
					list.Add(loopEdgeVertex[i]);
				}
				return EdgeLoopAnalyser.JudgeRightHandwise(list, ref direction);
			}
			if (num > num2)
			{
				direction = EdgeLoopAnalyser.RightHandwise._AntiClockwise;
			}
			else
			{
				direction = EdgeLoopAnalyser.RightHandwise._Clockwise;
			}
			return true;
		}

		private static LoopEdge SerializeEdge(LoopEdge edge, XYZ ptStart)
		{
			XYZ startPoint = edge.StartPoint;
			XYZ endPoint = edge.EndPoint;
			if (startPoint.IsAlmostEqualTo(ptStart, 0.0001))
			{
				return edge;
			}
			if (edge.IsArc)
			{
				return new LoopEdge(endPoint, startPoint, -edge.Bulge, edge.CurveId, edge.TheEdgeType);
			}
			return new LoopEdge(endPoint, startPoint, 0.0, edge.CurveId, edge.TheEdgeType);
		}

		private static XYZ GetOtherPoint(LoopEdge edge, XYZ ptCurrent)
		{
			XYZ startPoint = edge.StartPoint;
			XYZ endPoint = edge.EndPoint;
			if (ptCurrent.IsAlmostEqualTo(startPoint, 0.0001))
			{
				return endPoint;
			}
			if (ptCurrent.IsAlmostEqualTo(endPoint, 0.0001))
			{
				return startPoint;
			}
			return null;
		}

		private static XYZ GetNextPoint(XYZ currentNodePos, List<LoopEdge> nodeLinkedEdges, XYZ previousNodePos, double previousEdgeBugle, ref LoopEdge nextEdge)
		{
			XYZ otherPoint = EdgeLoopAnalyser.GetOtherPoint(nodeLinkedEdges[0], currentNodePos);
			XYZ otherPoint2 = EdgeLoopAnalyser.GetOtherPoint(nodeLinkedEdges[1], currentNodePos);
			if (previousNodePos.IsAlmostEqualTo(otherPoint, 0.0001) && previousNodePos.IsAlmostEqualTo(otherPoint2, 0.0001))
			{
				if (Geometry.IsEqual(previousEdgeBugle, nodeLinkedEdges[0].Bulge))
				{
					nextEdge = nodeLinkedEdges[1];
					return otherPoint;
				}
				nextEdge = nodeLinkedEdges[0];
				return otherPoint2;
			}
			else
			{
				if (previousNodePos.IsAlmostEqualTo(otherPoint, 0.0001))
				{
					nextEdge = nodeLinkedEdges[0];
					return otherPoint2;
				}
				if (previousNodePos.IsAlmostEqualTo(otherPoint2, 0.0001))
				{
					nextEdge = nodeLinkedEdges[1];
					return otherPoint;
				}
				return null;
			}
		}

		public enum RightHandwise
		{
			_Clockwise,
			_AntiClockwise
		}
	}
}
